#include <iostream>
#include <string>

using namespace std;

/*

    C++中实例化和具体化的区别：
        实例化：
            实例化是将一类对象或者模板，具体出一个对象或者函数来
            实例化是指在编译阶段根据模板定义和传递的参数类型生成特定类型的代码。
            在使用函数模板或类模板时，编译器会根据传递的实际参数类型自动实例化相应的模板。
            这样，模板在编译时被实例化为具体的函数或类，以处理特定类型的数据。实例化是在编译阶段发生的。
            带有纯虚函数的类是抽象类，不能实例化，类似与Java中的接口
        具体化：
            具体化是指为模板的特定数据类型提供明确的实现，以覆盖通用模板的行为。
            在有些情况下，通用的模板实现可能无法满足特定数据类型的需求
            这时可以通过显式具体化来为这些特定数据类型提供定制的实现。
            具体化会在编译阶段替代通用模板的实现，以处理特殊情况。

    template <typename T> 
        C++模板声明，表示一个泛型模板。其中，T是一个类型参数，可以在编译时替换为任意类型。
        template <typename T> 表示申明模板特化的开始
    template <>
        C++模板中的特化声明，用于为特定的类型或值提供模板函数或类的实现。它允许你为某个特定类型或值定制模板的行为，而不是使用默认的模板实现。
        使用在模板申明的后面，template <> 表示申明模板特化的开始

*/


/*
    在C++中，有几种情况下一个类不能实例化对象：

        1.抽象类（Abstract Class）：如果一个类被声明为抽象类，它包含至少一个纯虚函数（Pure Virtual Function），那么该类就不能实例化对象。纯虚函数是通过在函数声明中使用 "= 0" 来指定的，它们没有具体的实现，需要在派生类中实现。

        2.纯虚基类（Pure Virtual Base Class）：如果一个类从纯虚基类派生而来，但没有重写基类中的纯虚函数，那么派生类也将成为一个抽象类，不能实例化对象。

        3.私有构造函数（Private Constructor）：如果一个类的所有构造函数都被声明为私有（private），则无法从外部实例化该类的对象。这种情况下，通常使用单例模式或者工厂模式来控制对象的创建和访问。

        4.删除默认构造函数（Deleted Default Constructor）：如果一个类的默认构造函数被删除（deleted），则无法使用默认构造函数创建该类的对象。可以通过在类定义中使用 " = delete" 来删除默认构造函数。

        5.类型别名（Type Alias）：如果一个类只是作为类型别名使用，而不是作为具体的实现类，那么不能直接实例化该类的对象。

*/
#include <iostream>
#include <string>

using namespace std;

namespace TR
{
    // 模板申明的开始
    //实例化
    template <typename T>

    T add(T a, T b)
    {
        cout << "实例化调用" << endl;
        return T(a+b);
    }

    // 模板特化
    // 具体化
    template <>
    float add<float>(float a, float b)
    {
        cout << "具体化调用" << endl;
        return (a+b);
    }

};




int main(int argc, char *argv[])
{

    // 实例化的演示
    {

        using namespace TR;

        printf("整数的add: %d \n",add(1,2));
        printf("浮点数的add: %f \n",add(1.1,2.2));

        printf("******************\n");
        printf("整数的add: %d \n",add<int>(1,2));
        printf("浮点数的add: %f \n",add<float>(1.1,2.2));

    }

    return 0;
}